Passed
Push — master ( 6e3134...9d1f81 )
by Paul
04:23
created

Pagination.scrollToTop_   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
nc 12
nop 2
dl 0
loc 18
rs 9.0333
c 1
b 0
f 0
1
/** global: GLSR */
2
;(function() {
3
4
	'use strict';
5
6
	var GLSR_Pagination = function( el ) { // HTMLElement
7
		this.el = el;
8
		this.initEvents_();
9
	};
10
11
	GLSR_Pagination.prototype = {
12
		config: {
13
			hideClass: 'glsr-hide',
14
			linkSelector: '.glsr-navigation a',
15
			scrollTime: 468,
16
		},
17
18
		/** @return int */
19
		getChildIndexOfElement_: function( el ) { // HTMLElement
20
			var index = 0;
21
			while(( el = el.previousSibling )) {
22
				if( el.nodeType === 1 ) {
23
					index++;
24
				}
25
			}
26
			return index;
27
		},
28
29
		getSelector_: function( el ) {
30
			if( !el.nodeName )return;
31
			return this.getDomPath_( this.getDomPathNode_( el ));
32
		},
33
34
		/** @return string */
35
		getDomPath_: function( node ) { // object
36
			if( node.id !== '' ) {
37
				return '#' + node.id;
38
			}
39
			var root = '';
40
			if( node.parent ) {
41
				root = this.getDomPath_( node.parent ) + ' > ';
42
			}
43
			return root + node.name + ':nth-child(' + ( node.index + 1 ) + ')';
44
		},
45
46
		/** @return object */
47
		getDomPathNode_: function( el ) { // HTMLElement
48
			var node = {
49
				id: el.id,
50
				index: this.getChildIndexOfElement_( el ),
51
				name: el.nodeName.toLowerCase(),
52
				parent: null
53
			};
54
			if( el.parentElement && el.parentElement !== document.body ) {
55
				node.parent = this.getDomPathNode_( el.parentElement );
56
			}
57
			return node;
58
		},
59
60
		/** @return string */
61
		getElementClass_: function( el ) { // HTMLElement
62
			return el.className ? '.' + el.className.trim().replace( /\s+/g, '.' ) : '';
63
		},
64
65
		/** @return string */
66
		getElementId_: function( el ) { // HTMLElement
67
			return el.id ? '#' + el.id.trim() : '';
68
		},
69
70
		/** @return void */
71
		handleResponse_: function( location, selector, response ) { // string, string, string
72
			var newHTML = document.implementation.createHTMLDocument( 'x' );
73
			newHTML.documentElement.innerHTML = response;
74
			var newParentEl = selector ? newHTML.querySelectorAll( selector ) : '';
75
			if( newParentEl.length === 1 ) {
76
				this.el.innerHTML = newParentEl[0].innerHTML;
77
				this.scrollToTop_( this.el );
78
				this.el.classList.remove( this.config.hideClass );
79
				this.initEvents_();
80
				window.history.pushState( null, '', location );
81
				new GLSR.Excerpts( this.el );
82
				return;
83
			}
84
			window.location = location;
85
		},
86
87
		/** @return void */
88
		initEvents_: function() {
89
			var links = this.el.querySelectorAll( this.config.linkSelector );
90
			for( var i = 0; i < links.length; i++ ) {
91
				links[i].addEventListener( 'click', this.onClick_.bind( this ));
92
			}
93
		},
94
95
		/** @return void */
96
		onClick_: function( ev ) { // MouseEvent
97
			ev.preventDefault();
98
			var parentSelector = this.getSelector_( this.el );
99
			this.el.classList.add( this.config.hideClass );
100
			(new GLSR.Ajax()).get( ev.target.href, this.handleResponse_.bind( this, ev.target.href, parentSelector ));
101
		},
102
103
		/** @return void */
104
		scrollToTop_: function( el, offset ) { // HTMLElement, int
105
			offset = offset || 16; // 1rem
106
			var fixedElement;
107
			for( var i = 0; i < GLSR.ajaxpagination.length; i++ ) {
108
				fixedElement = document.querySelector( GLSR.ajaxpagination[i] );
109
				if( !fixedElement || window.getComputedStyle( fixedElement ).getPropertyValue( 'position' ) !== 'fixed' )continue;
110
				offset = offset + fixedElement.clientHeight;
111
			}
112
			var clientBounds = el.getBoundingClientRect();
113
			var offsetTop = clientBounds.top - offset;
114
			if( offsetTop > 0 )return; // if top is in view, don't scroll!
115
			this.scrollToTopStep_({
116
				endY: offsetTop,
117
				offset: window.pageYOffset,
118
				startTime: window.performance.now(),
119
				startY: el.scrollTop,
120
			});
121
		},
122
123
		/** @return void */
124
		scrollToTopStep_: function( context ) { // object
125
			var elapsed = ( window.performance.now() - context.startTime ) / this.config.scrollTime;
126
			elapsed = elapsed > 1 ? 1 : elapsed;
127
			var easedValue = 0.5 * ( 1 - Math.cos( Math.PI * elapsed ));
128
			var currentY = context.startY + ( context.endY - context.startY ) * easedValue;
129
			window.scroll( 0, context.offset + currentY ); // @todo what is this for again?
130
			if( currentY !== context.endY ) {
131
				window.requestAnimationFrame( this.scrollToTopStep_.bind( this, context ));
132
			}
133
		},
134
	};
135
136
	GLSR.Pagination = function() {
137
		this.navs = [];
138
		document.querySelectorAll( '.glsr-ajax-pagination' ).forEach( function( nodeItem ) {
139
			this.navs.push( new GLSR_Pagination( nodeItem ));
140
		}.bind( this ));
141
	};
142
})();
143